package com.iot.websocket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.iot.common.constant.Constants;
import com.iot.common.constant.HttpStatus;
import com.iot.common.core.domain.entity.SysUser;
import com.iot.common.core.domain.model.LoginUser;
import com.iot.common.enums.BizCode;
import com.iot.common.utils.StringUtils;
import com.iot.common.utils.spring.SpringUtils;
import com.iot.framework.mobile.token.LoginUserTokenHandlerMethodArgumentResolver;
import com.iot.framework.mobile.token.UserTokenManager;
import com.iot.framework.web.service.TokenService;
import com.iot.web.core.config.WebSocketConfig;
import com.iot.websocket.message.MqttClientMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;

/**
 * websocket服务
 * add by caoning
 */

@ServerEndpoint(value = "/ws/{token}", configurator = WebSocketConfig.class)
@Component
public class WebSocketServer {
    private static final Logger logger = LoggerFactory.getLogger(WebSocketServer.class);

    /**
     * 连接建立成功调用的方法
     *
     * @param session
     */
    @OnOpen
    public void onOpen(@PathParam(value= "token" ) String token, Session session) {
        if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX))
        {
            // web端访问
            token = token.replace(Constants.TOKEN_PREFIX, "");
            LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(token);
            if(loginUser == null){
                // 如果获取不到用户，比如用户session超时失效
                try {
                    session.getBasicRemote().sendText(String.valueOf(HttpStatus.UNAUTHORIZED));
                    session.close();
                } catch (IOException e) {
                    logger.info("loginUser为null，session关闭异常。token：{}， exceptionMsg：", token, e.getMessage());
                }
                return;
            }else{
                session.getUserProperties().put("sysUser", loginUser.getUser());
            }
        }else if(StringUtils.isNotEmpty(token) && token.startsWith(LoginUserTokenHandlerMethodArgumentResolver.LOGIN_TOKEN_KEY)){
            // 移动端访问
            SysUser sysUser = UserTokenManager.getToken(token).getSysUser();
            if(sysUser == null){
                // 如果获取不到用户，比如用户session超时失效
                try {
                    session.getBasicRemote().sendText(String.valueOf(HttpStatus.UNAUTHORIZED));
                    session.close();
                } catch (IOException e) {
                    logger.info("移动端登录sysUser为null，session关闭异常。token：{}， exceptionMsg：", token, e.getMessage());
                }
                return;
            }else{
                session.getUserProperties().put("sysUser", sysUser);
            }
        }
        WebSocketManager.addSession(session.getId(), session);
        //添加在线人数
        WebSocketManager.onlineCount++;
        logger.info("新连接接入。当前在线人数为：" + WebSocketManager.getOnlineCount());
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session, CloseReason closeReason) {
        WebSocketManager.removeSession(session.getId());
        //在线数减1
        WebSocketManager.onlineCount--;
        logger.info("有连接关闭。当前在线人数为：" + WebSocketManager.getOnlineCount());
    }

    /**
     * 收到客户端消息后调用
     *
     * @param message
     * @param session
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        logger.info("客户端发送的消息：" + message);
        try{
            WebSocketMessage msg = JSON.parseObject(message, WebSocketMessage.class);
            switch (BizCode.fromCode(msg.getBizCode())) {
                case SUBSCRIBE:
                    WebSocketManager.addSubscribe(msg, session);
                    break;
                case UNSUBSCRIBE:
                    WebSocketManager.removeSubscribe(msg, session);
                    break;
                case PUBLISH:
                    WebSocketMessagePublisher.publish(MqttClientMessage.getInstance(message));
                    break;
                case COMMON:
                    break;
                default:
                    break;
            }
        }catch (JSONException e){
            logger.info("客户端发送的消息转json异常");
        }
    }

    /**
     * 发生错误时调用
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        logger.error("----com.iot.earthquake.websocket-------出现异常");
        error.printStackTrace();
    }
}